#ifndef __BITARRAY_H
#define __BITARRAY_H

#include <fstream>
#include <sys/types.h>
#define nullptr NULL

namespace dataStructureZ
{
	typedef unsigned char 		uint8_t;
	
	
	template<class T> inline T upDiv(const T& a, const T& b)
	{
		return (a-1)/b + 1;
	}
	
	
	template<class lengthType = uint64_t> class ArrayBitController
	{
		public:typedef uint8_t byte_t;
		
		public:byte_t*		data;
		public:lengthType	bitLen;
		
		public:ArrayBitController
		(const lengthType length = 0, byte_t *const array = nullptr):
		data(array), bitLen(length){}
		
		public:void set(lengthType bitIndex, byte_t x)
		{
			lengthType	byteIndex	= bitIndex >> 3;
			byte_t      bitOffset	= bitIndex & 7;
			
			byte_t mask		= 1 << (7 ^ bitOffset);	// 00000000 | 00100000
			
			data[byteIndex] = (data[byteIndex] & (~mask)) | (x? mask: 0);
			/*
			a & ~b | b
			
			1111 1111
			0010 0000
			0010 0000
			
			0000 0000
			0010 0000
			0000 0000
			
			1011 0110
			1101 1111
			1001 0110
			*/
		}
		
		public:byte_t get(lengthType bitIndex) const
		{
			lengthType	byteIndex	= bitIndex >> 3;
			byte_t      bitOffset	= bitIndex & 7;
			//						= bitIndex ^ (bitIndex & 11111000)
			
			/*
			    29 / 8 = 3 % 5
				
			    0001 1101 = 29 A
				0000 0011 = 3  B = A>>3
				0001 1000 = 24 C = B<<3 = A&11111000
				
				0000 0101 = 5 = A-C
				
				0000 0101 = 5 = A^C
				
				b ^ (b & c)
				b & ~(b & c) | ~b & (b & c)
				b & (~b | ~c) | ~b & b & c
				(b & ~b | b & ~c) | ~b & b & c
				          b & ~c
						  
				10 % 8 = 2
				0000 1010 
				0000 0111
				0000 0010
				
				111
				101
				010
				
				1011 0110
				0010 0000
			*/
			return (data[byteIndex] & (1 << (7 ^ bitOffset)))? 1 : 0;
		}
		
		public:ArrayBitController& read(std::ifstream& ifs)
		{
			ifs.read(reinterpret_cast<char*>(&bitLen), sizeof(bitLen));
			lengthType byteLen = upDiv(bitLen, sizeof(byte_t));
			data = new byte_t[byteLen];
			ifs.read(reinterpret_cast<char*>(data), sizeof(byte_t) * byteLen);
			return *this;
		}
		
		public:void freeMem(void)
		{
			delete data;
			data = nullptr;
		}
		
		public:friend std::ifstream& operator >> (std::ifstream& ifs, ArrayBitController& abc)
		{
			abc.read(ifs);
			return ifs;
		}
		
		public:ArrayBitController& dump(std::ofstream ofs) const
		{
			ofs.write(reinterpret_cast<char*>(&bitLen), sizeof(bitLen));
			lengthType byteLen = upDiv(bitLen, sizeof(byte_t));
			ofs.write(reinterpret_cast<char*>(data), sizeof(byte_t) * byteLen);
			return *this;
		}
	};
	
};
#endif
